/**
 * 
 */
package edu.umd.clip.lm.storage;

import edu.umd.clip.lm.factors.*;
import edu.umd.clip.lm.model.*;
/**
 * @author Denis Filimonov <den@cs.umd.edu>
 *
 */
public abstract class AbstractProbTreeStorage implements AsyncProducer<AbstractProbTreeStorage.Key,OnDiskCompactProbTree> {

	public static class Key {
		final int modelid;
		final int clusterid;
		final long factorBits;
		public Key(int modelid, int clusterid, long factorBits) {
			this.modelid = modelid;
			this.clusterid = clusterid;
			this.factorBits = factorBits;
		}
		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + (int) (factorBits ^ (factorBits >>> 32));
			result = prime * result + modelid;
			result = prime * result + clusterid;
			return result;
		}
		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (!(obj instanceof Key))
				return false;
			Key other = (Key) obj;
			return clusterid == other.clusterid && modelid == other.modelid && factorBits == other.factorBits;
		}
		public int getClusterid() {
			return clusterid;
		}
		public long getFactorBits() {
			return factorBits;
		}
		public int getModelid() {
			return modelid;
		}
		
		public String toString() {
			return String.format("[%d-%d %s]", modelid, clusterid, FactorTuple.toStringNoNull(factorBits));
		}
	}

	/**
	 * @return whether additional measures should be taken to reduce false positives 
	 */
	public boolean hasFalsePositives() {
		return false;
	}
	
	public OnDiskCompactProbTree getProbTree(int modelid, int clusterid, FactorTuple word) {
		return getProbTree(modelid, clusterid, word.getBits());
	}
	
	public OnDiskCompactProbTree getProbTree(int modelid, int clusterid, long factorBits) {
		return getProbTree(new Key(modelid, clusterid, factorBits));
	}
	
	public abstract OnDiskCompactProbTree getProbTree(Key key);
	
	
	/**
	 * @param modelid
	 * @param clusterid
	 * @param totalCount
	 * 
	 * must be called before any setProbTree() calls involving the same model and cluster
	 * most storages ignore it, though
	 */
	public void setTotalClusterCount(int modelid, int clusterid, long totalCount) {}
	
	public void setProbTree(int modelid, int clusterid, FactorTuple word, OnDiskCompactProbTree probTree) {
		setProbTree(modelid, clusterid, word.getBits(), probTree);
	}
	
	public void setProbTree(int modelid, int clusterid, long factorBits, OnDiskCompactProbTree probTree) {
		setProbTree(new Key(modelid, clusterid, factorBits), probTree);
	}
	abstract public void setProbTree(Key key, OnDiskCompactProbTree probTree);
	
	abstract public String getStats();

	// asynchroneous API
	public void requestProbTree(int modelid, int clusterid, FactorTuple word) {
		requestProbTree(modelid, clusterid, word.getBits());
	}
	
	public void requestProbTree(int modelid, int clusterid, long factorBits) {
		requestProbTree(new Key(modelid, clusterid, factorBits));
	}
	
	abstract protected void requestProbTree(Key key);
	
	public abstract void closeAll();
}
